package javax.per.toolkit.mail;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Message.RecipientType;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import javax.per.toolkit.tools.Log;

/**
 * 
 * @author yl34569
 *
 */
public class MailReceiver {
	
	private String userName;
	private String password;
	private int pop3Port=110;
	private String protocol="pop3";
	private String pop3Server ;    //pop3.126.com
	private boolean isDebug=false;
	private String mailFolder="INBOX";
	private int openFolderMode=Folder.READ_WRITE;
	private String dateFormat="yyyy-MM-dd HH:mm:ss";
	private List<MailReceiveInfo> receiveInfo=new ArrayList<MailReceiveInfo>();
	
	/**
	 * Default constructor
	 */
	public MailReceiver(){
		
	}
	
	/**
	 * Constructor
	 * @param userName user name
	 * @param password the password
	 * @param pop3Server the pop3 server
	 */
	public MailReceiver(String userName,String password,String pop3Server){
		this.userName=userName;
		this.password=password;
		this.pop3Server=pop3Server;
	}
	
	/**
	 * Receive all of the mails
	 * @throws MessagingException
	 * @throws IOException
	 */
	public void receiveAll() throws MessagingException, IOException{
		Folder folder=this.init();
		Message[] msgs=folder.getMessages();
		for(Message msg:msgs){
			resolver((MimeMessage)msg);
		}
	}
	
	/**
	 * Receive the specified number of the mails
	 * @param receCount the number of the mails to be received.
	 * @throws MessagingException
	 * @throws IOException
	 */
	public void receivePart(int receCount) throws MessagingException, IOException{
		Folder folder=this.init();
		int count=folder.getMessageCount();
		Message[] msgs=null;
		if(count<receCount)
			msgs=folder.getMessages(1, count);
		else
			msgs=folder.getMessages(count-receCount+1, count);
		for(Message msg:msgs){
			resolver((MimeMessage)msg);
		}
	}
	
	
	/**
	 * Do something initialization.
	 * @return a instance of a Folder class.
	 * @throws MessagingException
	 */
	protected Folder init() throws MessagingException{
		Properties pro=new Properties();
		pro.put("mail.store.protocol", this.protocol);
		pro.put("mail.pop3.host", this.pop3Server);
		
		Session session=Session.getDefaultInstance(pro);
		session.setDebug(this.isDebug);
		Store store=session.getStore();
		
		store.connect(this.pop3Server,this.userName,this.password);
		
		Folder folder=store.getFolder(this.mailFolder);
		folder.open(openFolderMode);
		return folder;
	}
	
	/**
	 * To analysis a mail.
	 * @param msg the message.
	 * @throws MessagingException
	 * @throws IOException
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	protected void resolver(MimeMessage msg) throws MessagingException, IOException{
		MailReceiveInfo recInfo=new MailReceiveInfo();
		recInfo.setMessageId(msg.getMessageID());
		recInfo.setMessageNumber(msg.getMessageNumber());
		String[] tmp=this.getFrom(msg);
		recInfo.setFromAddress(tmp[0]);
		recInfo.setFromPerson(tmp[1]);
		List[] lis=this.getTo(msg);
		recInfo.setToAddress(lis[0]);
		recInfo.setToPerson(lis[1]);
		recInfo.setCcAddress(lis[2]);
		recInfo.setCcPerson(lis[3]);
		recInfo.setSubject(this.getSubject(msg));
		recInfo.setDate(this.getSentDate(msg));
		recInfo.setContent(this.getContent(msg));
		recInfo.setHasReplySign(this.getReplySign(msg));
		recInfo.setNew(this.isNew(msg));
		//TODO:
		
		this.receiveInfo.add(recInfo);
	}
	
	/**
	 * Get the subject of a mail.
	 * @param msg the message.
	 * @return the subject.
	 * @throws UnsupportedEncodingException
	 * @throws MessagingException
	 */
	protected String getSubject(MimeMessage msg) throws UnsupportedEncodingException, MessagingException{
		String subject=MimeUtility.decodeText(msg.getSubject());
		if(subject==null)
			subject="";
		return subject;
	}
	
	/**
	 * Get the send date of a mail.
	 * @param msg the message.
	 * @return the send date.
	 * @throws MessagingException
	 */
	protected String getSentDate(MimeMessage msg) throws MessagingException{
		Date sendDate=msg.getSentDate();
		SimpleDateFormat sdf=new SimpleDateFormat(this.dateFormat);
		return sdf.format(sendDate);
	}
	
	/**
	 * Get the address where a mail send from.
	 * @param msg the message.
	 * @return the address.
	 * @throws MessagingException
	 */
	protected String[] getFrom(MimeMessage msg) throws MessagingException{
		String[] result=new String[2];
		InternetAddress[] address=(InternetAddress[])msg.getFrom();
		String fromAddress=address[0].getAddress();
		if(fromAddress==null)
			fromAddress="";
		String fromPerson=address[0].getPersonal();
		if(fromPerson==null)
			fromPerson="";
		result[0]=fromAddress;
		result[1]=fromPerson;
		return result;
	}
	
	/**
	 * Get the address a mail send to.
	 * @param msg the message.
	 * @return the address.
	 * @throws MessagingException
	 * @throws UnsupportedEncodingException
	 */
	@SuppressWarnings("unchecked")
	protected List<String>[] getTo(MimeMessage msg) throws MessagingException, UnsupportedEncodingException{
		List<String>[] result=new ArrayList[4];
		List<String> toAddress=new ArrayList<String>();
		List<String> toPerson=new ArrayList<String>();
		List<String> ccAddress=new ArrayList<String>();
		List<String> ccPerson=new ArrayList<String>();
		InternetAddress[] address=(InternetAddress[])msg.getRecipients(RecipientType.TO);
		if(address!=null){
			for(InternetAddress add:address){
				String mail=add.getAddress();
				if(mail==null)
					mail="";
				MimeUtility.decodeText(mail);
				toAddress.add(mail);
				String per=add.getPersonal();
				if(per==null)
					per="";
				MimeUtility.decodeText(per);
				toPerson.add(per);
			}
		}
		
		address=(InternetAddress[])msg.getRecipients(RecipientType.CC);
		if(address!=null){
			for(InternetAddress add:address){
				String mail=add.getAddress();
				if(mail==null)
					mail="";
				MimeUtility.decodeText(mail);
				ccAddress.add(mail);
				String per=add.getPersonal();
				if(per==null)
					per="";
				MimeUtility.decodeText(per);
				ccPerson.add(per);
			}
		}
		
		result[0]=toAddress;
		result[1]=toPerson;
		result[2]=ccAddress;
		result[3]=ccPerson;
		return result;
	}
	
	
	/**
	 * Get the content of a mail.
	 * @param msg the message.
	 * @return the content.
	 * @throws MessagingException
	 * @throws IOException
	 */
	protected String getContent(MimeMessage msg) throws MessagingException, IOException{
		StringBuffer buf=new StringBuffer();
		getContentLoop(msg,buf);
		return buf.toString();
	}
	
	/**
	 * Loop to get the content of a mail.
	 * @param msg the message.
	 * @param buf a instance of a StringBuffer class.
	 * @throws MessagingException
	 * @throws IOException
	 */
	protected void getContentLoop(Part msg,StringBuffer buf) throws MessagingException, IOException{
		String contentType=msg.getContentType();
		int nameIndex=contentType.indexOf("name");
		boolean conname=false;
		if(nameIndex!=-1)
			conname=true;
		if(msg.isMimeType("text/plain")&&!conname){
			buf.append((String)msg.getContent());
		}
		else if(msg.isMimeType("text/html")&&!conname)
			buf.append((String)msg.getContent());
		else if(msg.isMimeType("multipart/*")){
			Multipart multipart=(Multipart)msg.getContent();
			int count=multipart.getCount();
			for(int i=0;i<count;i++){
				getContentLoop(multipart.getBodyPart(i),buf);
			}
		}else if(msg.isMimeType("message/rfc822")){
			getContentLoop((Part)msg.getContent(),buf);
		}
	}
	
	/**
	 * Get the reply sign of a mail.
	 * @param msg the message.
	 * @return the sign.
	 * @throws MessagingException
	 */
	protected boolean getReplySign(MimeMessage msg) throws MessagingException{
		boolean replySign=false;
		String needReply[]=msg.getHeader("Disposition-Notification-TO");
		if(needReply!=null)
			replySign=true;
		return replySign;
	}
	
	/**
	 * Get the message id of a mail.
	 * @param msg the message.
	 * @return the message id.
	 * @throws MessagingException
	 */
	protected String getMessageId(MimeMessage msg) throws MessagingException{
		return msg.getMessageID();
	}
	
	/**
	 * Determines if the mail is new.
	 * @deprecated pop3 can't be work correctly.
	 * @param msg the message.
	 * @return true stands of new.else false.
	 * @throws MessagingException
	 */
	protected boolean isNew(MimeMessage msg) throws MessagingException{
		Flags flags=msg.getFlags();
		Log.getLogger().debug(flags.equals(Flags.Flag.SEEN));
		if(flags.contains(Flags.Flag.SEEN))
			return true;
		return false;
	}
	
	
	public boolean isDebug() {
		return isDebug;
	}

	public void setDebug(boolean isDebug) {
		this.isDebug = isDebug;
	}

	public String getpop3Server () {
		return pop3Server ;
	}

	public void setpop3Server (String pop3Server ) {
		this.pop3Server  = pop3Server ;
	}

	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public int getpop3Port() {
		return pop3Port;
	}
	public void setpop3Port(int pop3Port) {
		this.pop3Port = pop3Port;
	}

	public String getprotocol() {
		return protocol;
	}

	public void setprotocol(String protocol) {
		this.protocol = protocol;
	}

	public String getMailFolder() {
		return mailFolder;
	}

	public void setMailFolder(String mailFolder) {
		this.mailFolder = mailFolder;
	}

	public int getOpenFolderMode() {
		return openFolderMode;
	}

	public void setOpenFolderMode(int openFolderMode) {
		this.openFolderMode = openFolderMode;
	}


	public List<MailReceiveInfo> getReceiveInfo() {
		return receiveInfo;
	}

	public String getDateFormat() {
		return dateFormat;
	}

	public void setDateFormat(String dateFormat) {
		this.dateFormat = dateFormat;
	}
	
	/**
	 * Example for using this class.
	 * @param args command line.
	 * @throws MessagingException
	 * @throws IOException
	 */
	public static void main(String[] args) throws MessagingException, IOException{
		/*
		 * Test for receiving mails.
		 */
		MailReceiver rece=new MailReceiver();
		rece.setUserName("lou_yj@126.com");
		rece.setPassword("wozai2011");
		rece.setpop3Server("pop3.126.com");
		rece.setDebug(true);
		rece.receiveAll();
		List<MailReceiveInfo> list=rece.getReceiveInfo();
		Log.getLogger().debug(list.size());
		for(MailReceiveInfo in:list){
			Log.getLogger().debug(in.getMessageId());
			Log.getLogger().debug(in.getMessageNumber());
			Log.getLogger().debug(in.getFromAddress());
			Log.getLogger().debug(in.getFromPerson());
			Log.getLogger().debug(in.getToAddress().get(0));
			Log.getLogger().debug(in.getToPerson().get(0));
			Log.getLogger().debug(in.getSubject());
			Log.getLogger().debug(in.getDate());
			Log.getLogger().debug(in.getContent());
			Log.getLogger().debug(in.isHasReplySign());
			Log.getLogger().debug(in.isNew());
			Log.getLogger().debug("------------------------------------");
		}
		
	}
	
	
	
}
